package de.justphil.tcg.tcgserver.rest.resources;


import java.util.ArrayList;
import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import org.slf4j.Logger;

import com.yammer.metrics.annotation.Timed;

import de.justphil.tcg.tcgserver.commons.exceptions.TCGException;
import de.justphil.tcg.tcgserver.commons.i18n.Error;
import de.justphil.tcg.tcgserver.commons.config.RestConfig;
import de.justphil.tcg.tcgserver.commons.management.DataManager;
import de.justphil.tcg.tcgserver.commons.domain.CardInstance;
import de.justphil.tcg.tcgserver.commons.domain.Deck;
import de.justphil.tcg.tcgserver.commons.domain.User;
import de.justphil.tcg.tcgserver.commons.domain.wrappers.AuthUser;
import de.justphil.tcg.tcgserver.commons.domain.wrappers.Credentials;
import de.justphil.tcg.tcgserver.commons.domain.wrappers.ListRes;
import de.justphil.tcg.tcgserver.commons.domain.wrappers.ShallowCardInstance;
import de.justphil.tcg.tcgserver.commons.domain.wrappers.ShallowDeck;
import de.justphil.tcg.tcgserver.commons.domain.wrappers.SingleObjectRes;
import de.justphil.tcg.tcgserver.commons.management.Application;
import de.justphil.tcg.tcgserver.rest.db.UserRegistrar;
import de.justphil.tcg.tcgserver.rest.resources.base.AbstractResource;
import de.justphil.tcg.tcgserver.rest.validators.NewUserValidator;
import static de.justphil.tcg.tcgserver.commons.logging.TCGLogging.*;



@Path("/user")
public class UserResource extends AbstractResource {
	
	private static final Logger log = restLogger(UserResource.class);
	
	private final DataManager dataManager;
	
	
	public UserResource() {
		dataManager = Application.getDataManager();
	}
	
	
	@GET
	@Path("/auth")
    @Produces(MediaType.APPLICATION_JSON)
	public Response authUser(	@HeaderParam(RestConfig.REQ_HEADER_ACCEPT_LANGUAGE) String locale,
								@HeaderParam(RestConfig.REQ_HEADER_AUTHORIZATION) String authHeader) {
		
		User user = aaa(dataManager, locale, authHeader);
		
		return ok( new SingleObjectRes<AuthUser>( new AuthUser( user.getId() ) ) );
	}
	
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/{userId: [0-9]+}")
    @Timed
    public Response getUser( @PathParam("userId") long userId, @HeaderParam(RestConfig.REQ_HEADER_ACCEPT_LANGUAGE) String locale ) {
    	try {
    		User user = dataManager.getUserByIdPublicly(userId);
    		
    		// TODO: Kill debug code!
    		//log.debug(user.toString());
    		
    		return ok( new SingleObjectRes<User>(user) );
    	}
    	catch (TCGException e) {
    		return err(e.getMessage(), (Status) e.getExtra(), locale);
    	}
    }
    
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Timed
    public Response createUser(User user, @HeaderParam(RestConfig.REQ_HEADER_ACCEPT_LANGUAGE) String locale) {
    	try {
    		Credentials c = new NewUserValidator().validatePost(dataManager, user);
    		
    		new UserRegistrar().registerNewUser(Application.getEntityManagerFactory(), dataManager, c);
    		
    		return created();
    	}
    	catch (TCGException e) {
    		return err(e.getMessage(), (Status) e.getExtra(), locale);
    	}
    }
    
    /* ######################################################################## */
	/* ######################################################################## */
	/* ######################################################################## */
    
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/{userId: [0-9]+}/decks")
    public Response getUserDecks( 	@PathParam("userId") long userId,
    								@HeaderParam(RestConfig.REQ_HEADER_ACCEPT_LANGUAGE) String locale,
    								@HeaderParam(RestConfig.REQ_HEADER_AUTHORIZATION) String authHeader ) {
    	
    	User user = aaa(dataManager, locale, authHeader);
    	
    	try {
    		if (user.getId() != userId) {
    			throw new TCGException(Error.CLIENT_ERROR_NOT_DECK_OWNER, Response.Status.FORBIDDEN);
    		}
    		
    		// TODO: Kill debug code
    		log.debug("User '{}' has {} deck(s).", user.getUsername(), user.getDecks().size());
    		
    		List<ShallowDeck> shallowDeckList = new ArrayList<ShallowDeck>(user.getDecks().size());
    		
    		for (Deck d : user.getDecks()) {
    			shallowDeckList.add( new ShallowDeck( d ) );
    		}
    		
    		return ok( new ListRes<ShallowDeck>( shallowDeckList ) );
    	}
    	catch (TCGException e) {
    		return err(e.getMessage(), (Status) e.getExtra(), locale);
    	}
    }
    
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/{userId: [0-9]+}/cards")
    public Response getUserCards( 	@PathParam("userId") long userId,
    								@HeaderParam(RestConfig.REQ_HEADER_ACCEPT_LANGUAGE) String locale,
    								@HeaderParam(RestConfig.REQ_HEADER_AUTHORIZATION) String authHeader ) {
    	
    	User user = aaa(dataManager, locale, authHeader);
    	
    	try {
    		if (user.getId() != userId) {
    			throw new TCGException(Error.CLIENT_ERROR_NOT_CARD_OWNER, Response.Status.FORBIDDEN);
    		}
    		
    		List<ShallowCardInstance> shallowCis = new ArrayList<ShallowCardInstance>(user.getCardInstances().size());
    		
    		for (CardInstance ci : user.getCardInstances()) {
    			shallowCis.add( new ShallowCardInstance( ci ) );
    		}
    		
    		return ok( new ListRes<ShallowCardInstance>( shallowCis ) );
    	}
    	catch (TCGException e) {
    		return err(e.getMessage(), (Status) e.getExtra(), locale);
    	}
    }
}
